﻿using F2B.Orchard.Schedule.Models;
using F2B.Orchard.Schedule.Services;
using F2B.Orchard.Schedule.Settings;
using Orchard;
using Orchard.Autoroute.Services;
using Orchard.ContentManagement;
using Orchard.Core.Contents;
using Orchard.Core.Title.Models;
using Orchard.Environment.Extensions;
using Orchard.Projections.Services;
using Orchard.Tags.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Web.Http.Routing;
using Orchard.DisplayManagement;
using Orchard.Mvc;
using Orchard.UI.Navigation;

namespace F2B.Orchard.Schedule.Controllers
{
    using Occurrence = Dictionary<string, object>;
    
    [OrchardFeature("F2B.Orchard.CalendarLayout")]
    public class UpcomingLayoutController : ApiController
    {
        private readonly IScheduleService _scheduleService;
        private readonly IScheduleLayoutService _scheduleLayoutService;
        private readonly IOrchardServices _orchardServices;
        private readonly ISlugService _slugService;

        private static DateTime UnixEpochTime = new DateTime(1970, 1, 1);

        public UpcomingLayoutController(
            IScheduleService scheduleService,
            IScheduleLayoutService scheduleLayoutService,
            IOrchardServices orchardServices,
            ISlugService slugService) {
            
            _scheduleService = scheduleService;
            _scheduleLayoutService = scheduleLayoutService;
            _orchardServices = orchardServices;
            _slugService = slugService;
        }

        public IEnumerable<Occurrence> Get(int id, int page = 1) {
            DateTime startDate = DateTime.UtcNow;
            int count = 3; // TODO: take this from the ProjectionPart
            int skip = (page - 1) * count;

            IEnumerable<ContentItem> contentItems = _scheduleLayoutService.GetProjectionContentItems(id);
            List<Occurrence> occurrences = new List<Occurrence>();

            if (contentItems == null) return occurrences;

            Dictionary<IContent, ScheduleData> ScheduleMap =
                contentItems
                .Select(c => new { k = (IContent)c, v = new ScheduleData(c, Url, _slugService, _orchardServices) })
                .ToDictionary(c => c.k, c => c.v);

            var upcomingScheduleParts = contentItems
                .Select(c => c.As<SchedulePart>())
                .Where(s => _scheduleLayoutService.DateInFuture(s));

            // TODO: Gauranteed to be a way to make this more efficient
            List<ScheduleOccurrence> scheduleOccurrences = new List<ScheduleOccurrence>();
            int beforeCount;
            int afterCount = 0;

            while (afterCount < page * count) {
                beforeCount = scheduleOccurrences.Count;
                GetMoreOccurrences(upcomingScheduleParts, startDate, ref scheduleOccurrences);
                afterCount = scheduleOccurrences.Count;

                if (afterCount > beforeCount) {
                    if (scheduleOccurrences.Count > 0) {
                        startDate = scheduleOccurrences.Min(so => so.Start).AddSeconds(1);
                    }
                    else {
                        break;
                    }
                }
                else { // We are not gaining any more occurrences
                    break;
                }
            }

            occurrences = scheduleOccurrences.Select(o => _scheduleLayoutService.GetOccurrenceObject(o, ScheduleMap[o.Source])).ToList();

            return occurrences;            
        }

        private void GetMoreOccurrences(IEnumerable<SchedulePart> upcomingScheduleParts, DateTime startDate, ref List<ScheduleOccurrence> scheduleOccurrences) {
            foreach (var schedulePart in upcomingScheduleParts) {
                var nextOccurrence = _scheduleService.GetNextOccurrence(schedulePart, startDate);
                if (nextOccurrence != null) {
                    if (!scheduleOccurrences.Select(so =>
                        so.Source == nextOccurrence.Source &&
                        so.Start == nextOccurrence.Start).Any()) {

                        scheduleOccurrences.Add(nextOccurrence);
                    }
                }
            }
        }
    }
}